package biz.datalk.industrialland.admin.modules.system.service.impl;

import biz.datalk.commons.utils.IdProvider;
import biz.datalk.commons.utils.MapUtil;
import biz.datalk.industrialland.admin.component.shiro.CustomLoginUser;
import biz.datalk.industrialland.admin.modules.system.mapper.ISysDictExtMapper;
import biz.datalk.industrialland.admin.modules.system.operator.SysDictAndItemCacheManager;
import biz.datalk.industrialland.admin.modules.system.pojo.dto.SysDictDTO;
import biz.datalk.industrialland.admin.modules.system.service.ISysDictService;
import biz.datalk.industrialland.admin.modules.util.ShiroUtil;
import biz.datalk.industrialland.common.def.CommonConstant;
import biz.datalk.industrialland.common.def.enums.DBYNEnum;
import biz.datalk.industrialland.common.exception.ServiceException;
import biz.datalk.industrialland.common.result.UnifyResult;
import biz.datalk.industrialland.common.result.UnifyResultUtil;
import biz.datalk.industrialland.common.util.EntityIdUtils;
import biz.datalk.industrialland.common.util.I18NUtil;
import biz.datalk.industrialland.mbg.mapper.SysDictMapper;
import biz.datalk.industrialland.mbg.pojo.po.SysDict;
import biz.datalk.industrialland.mbg.pojo.po.SysDictItem;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Priority;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tarofang@163.com
 * @date 2019-12-23
 */
@Slf4j
@Service("sysDictServiceBasicImpl")
@Priority(CommonConstant.INITIAL_PRIORITY)
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class SysDictServiceBasicImpl implements ISysDictService {

    private final SysDictMapper sysDictMapper;
    private final ISysDictExtMapper sysDictExtMapper;
    private final SysDictAndItemCacheManager sysDictAndItemCacheManager;

    @Autowired
    public SysDictServiceBasicImpl(
            SysDictMapper sysDictMapper, //
            ISysDictExtMapper sysDictExtMapper, //
            SysDictAndItemCacheManager sysDictAndItemCacheManager) {
        this.sysDictMapper = sysDictMapper;
        this.sysDictExtMapper = sysDictExtMapper;
        this.sysDictAndItemCacheManager = sysDictAndItemCacheManager;
    }

    @Override
    public UnifyResult list(SysDictDTO sysDictDTO) {

        QueryWrapper<SysDict> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc(SysDict.COL_UPDATE_TIME);
        if (StringUtils.isNotBlank(sysDictDTO.getDictName())) {
            queryWrapper.like(SysDict.COL_DICT_NAME, sysDictDTO.getDictName().trim());
        }
        if (StringUtils.isNotBlank(sysDictDTO.getDictCode())) {
            queryWrapper.like(SysDict.COL_DICT_CODE, sysDictDTO.getDictCode().trim());
        }

        IPage<SysDict> page = new Page<>(sysDictDTO.getPageNumber(), sysDictDTO.getPageSize());
        IPage<SysDict> pageInfo = sysDictMapper.selectPage(page, queryWrapper);

        return UnifyResult.success().mapData().put("rows", pageInfo.getRecords()).put("total", pageInfo.getTotal());
    }

    @Override
    public UnifyResult add(SysDictDTO sysDictDTO) {
        CustomLoginUser customLoginUser = ShiroUtil.currentLoginUser();
        sysDictAndItemCacheManager.clearAll();
        UnifyResult result = checkDuplicateDictCode(sysDictDTO, Boolean.FALSE);
        if (UnifyResultUtil.isFail(result)) {
            return result;
        }

        Date now = new Date();
        SysDict dict = new SysDict();
        dict.setDictId(IdProvider.createUUIDId());
        dict.setDictName(sysDictDTO.getDictName());
        dict.setDictCode(sysDictDTO.getDictCode());
        dict.setDescription(StringUtils.trimToEmpty(sysDictDTO.getDescription()));
        dict.setIsDelete(DBYNEnum.N.name());
        dict.setIsValid(DBYNEnum.Y.name());
        dict.setCreateBy(customLoginUser.getId());
        dict.setCreateName(customLoginUser.getRealname());
        dict.setCreateTime(now);
        dict.setUpdateBy(customLoginUser.getId());
        dict.setUpdateName(customLoginUser.getRealname());
        dict.setUpdateTime(now);

        sysDictMapper.insertSelective(dict);
        return UnifyResult.success();
    }

    @Override
    public UnifyResult edit(SysDictDTO sysDictDTO) {
        sysDictAndItemCacheManager.clearAll();
        UnifyResult result = checkDuplicateDictCode(sysDictDTO, Boolean.TRUE);
        if (UnifyResultUtil.isFail(result)) {
            return result;
        }

        SysDict exists = sysDictMapper.selectById(sysDictDTO.getId());

        CustomLoginUser customLoginUser = ShiroUtil.currentLoginUser();

        SysDict sysDict = new SysDict();
        sysDict.setId(sysDictDTO.getId());
        sysDict.setDictId(exists.getDictId());
        sysDict.setDictName(sysDictDTO.getDictName());
        sysDict.setDictCode(sysDictDTO.getDictCode());
        String description = sysDictDTO.getDescription();
        if (StringUtils.isNotBlank(description)) {
            sysDict.setDescription(description.trim());
        }
        sysDict.setUpdateBy(customLoginUser.getId());
        sysDict.setUpdateName(customLoginUser.getRealname());
        sysDict.setUpdateTime(new Date());
        String isDelete = sysDictDTO.getIsDelete();
        if (StringUtils.isNotBlank(isDelete) && StringUtils.equalsAny(isDelete, DBYNEnum.Y.name(), DBYNEnum.N.name())) {
            sysDict.setIsDelete(isDelete);
        }
        String isValid = sysDictDTO.getIsValid();
        if (StringUtils.isNotBlank(isValid) && StringUtils.equalsAny(isValid, DBYNEnum.Y.name(), DBYNEnum.N.name())) {
            sysDict.setIsValid(isValid);
        }

        sysDictMapper.updateByPrimaryKeySelective(sysDict);
        sysDictAndItemCacheManager.removeSysDictCacheGroup(sysDict.getDictId(), sysDict.getDictCode());
        return UnifyResult.success();
    }

    @Override
    public UnifyResult batchDelete(SysDictDTO sysDictDTO) {
        List<Long> sysids = EntityIdUtils.parseIds(sysDictDTO.getSysids());
        if (CollectionUtils.isEmpty(sysids)) {
            log.debug("Invalid sysids");
            return UnifyResult.fail(I18NUtil.getMsg("sysdict.no.exists.or.delete"));
        }

        List<SysDict> sysDicts = sysDictMapper.selectBatchIds(sysids);
        if (CollectionUtils.size(sysDicts) != sysids.size()) {
            log.debug("Invalid sysids. [sysids={}]", sysDictDTO.getSysids());
            return UnifyResult.fail(I18NUtil.getMsg("sysdict.no.exists.or.delete"));
        }

        SysDict params = new SysDict();
        CustomLoginUser customLoginUser = ShiroUtil.currentLoginUser();
        params.setUpdateBy(customLoginUser.getId());
        params.setUpdateName(customLoginUser.getRealname());
        params.setUpdateTime(new Date());
        params.setIsDelete(DBYNEnum.Y.name());
        params.setIsValid(DBYNEnum.N.name());

        UpdateWrapper<SysDict> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in(SysDict.COL_ID, sysids);

        int resInt = sysDictMapper.update(params, updateWrapper);
        if (resInt != CollectionUtils.size(sysids)) {
            throw new ServiceException(I18NUtil.getMsg("sysdict.batch.delete.fail"));
        }

        List<String> dictIdList = sysDicts.stream().map(SysDict::getDictId).collect(Collectors.toList());

        sysDictAndItemCacheManager.batchRemoveSysDictCacheGroup(dictIdList, null);

        return UnifyResult.success();
    }

    @Override
    public UnifyResult delete(SysDictDTO sysDictDTO) {
        long id = sysDictDTO.getId();
        SysDict sysDict = sysDictMapper.selectById(id);
        if (sysDict == null) {
            throw new ServiceException("字典不存在或已被删除");
        }
        int resInt = sysDictMapper.deleteById(id);
        if (resInt != 1) {
            throw new ServiceException(I18NUtil.getMsg("sysdict.delete.fail"));
        }
        sysDictAndItemCacheManager.removeSysDictCacheGroup(sysDict.getDictId(), sysDictDTO.getDictCode());
        return UnifyResult.success();
    }

    @Override
    public UnifyResult load(String dictCode) {
        String regex = "^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$";
        if (!StringUtils.trimToEmpty(dictCode).matches(regex)) {
            return UnifyResult.fail(I18NUtil.getMsg("sysdict.invalid.dictCode"));
        }

        // item_text item_value
        List<Map<String, Object>> resList = null;
        List<SysDictItem> itemList = sysDictAndItemCacheManager.getSysDictItemList(null, dictCode);
        if (itemList != null) {
            resList = extractDictItemMapList(itemList);

        } else {
            resList = sysDictExtMapper.selectMapByDictCode(dictCode.trim());
            resList = CollectionUtils.isEmpty(resList) ? Collections.emptyList() : resList;
            resList = MapUtil.underline2Hump(resList);

        }

        return UnifyResult.success().setData(resList);
    }

    private UnifyResult checkDuplicateDictCode(SysDictDTO sysDictDTO, Boolean isUpdate) {
        String dictCode = sysDictDTO.getDictCode().trim();
        SysDict dict = sysDictAndItemCacheManager.getSysDict(null, dictCode);
        if (dict == null) {
            dict = sysDictExtMapper.selectByDictCode(dictCode);

        }

        if (dict == null) {
            return UnifyResult.success();
        }

        // 添加数据
        if (!isUpdate) {
            return UnifyResult.fail(I18NUtil.getMsg("sysdict.duplicate.diceCode"));
        }

        // 更新数据
        SysDict exists = sysDictMapper.selectById(sysDictDTO.getId());
        if (exists == null) {
            return UnifyResult.fail(I18NUtil.getMsg("sysdict.no.exists.or.delete"));
        }

        if (!exists.getDictCode().equals(dict.getDictCode())) {
            return UnifyResult.fail(I18NUtil.getMsg("sysdict.duplicate.diceCode"));
        }

        return UnifyResult.success();
    }

    private static List<Map<String, Object>> extractDictItemMapList(List<SysDictItem> itemList) {
        if (itemList == null) {
            return null;

        }

        List<Map<String, Object>> itemMapList = new ArrayList<Map<String, Object>>(itemList.size());
        for (SysDictItem item : itemList) {
            if ((item != null) && (item.getItemValue() != null)) {
                Map<String, Object> itemMap = new HashMap<String, Object>();
                itemMap.put("itemValue", item.getItemValue());
                itemMap.put("itemText", item.getItemText());
                itemMapList.add(itemMap);

            }

        }

        return itemMapList;

    }

}
